﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using Lucene.Net.Store;
using Lucene.Net.Index;
using Lucene.Net.Documents;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;

namespace iReaper.Source
{
    public class IndexBuilder
    {
        static string _indexPath = "";

        public static void Init()
        {
            // Get server
            string relativePath = System.Web.Configuration.WebConfigurationManager.AppSettings["IndexData"];
            _indexPath = HttpContext.Current.Server.MapPath(relativePath) ;
            // Register event handler
            OriginalContentManager.Current.OnXmlSynchorized += new EventHandler(OnXmlSync_CreateIndex);
        }

        private static void OnXmlSync_CreateIndex(object sender, EventArgs e)
        {
            string infoXmlPath = OriginalContentManager.Current.InfoXmlPath;
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(infoXmlPath);

            RAMDirectory dir = new RAMDirectory();
            IndexWriter writer = new IndexWriter(dir, new Lucene.Net.Analysis.CJK.CJKAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);

            foreach (XmlNode node in xmldoc.SelectNodes("//R"))
            {
                Document doc = new Document();
                // ID
                var newsId = node.SelectSingleNode("newsID");

                doc.Add(new Field("id", newsId.InnerText, Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));
                // Headline
                var headline = node.SelectSingleNode("headline");
                doc.Add(new Field("", headline.InnerText, Field.Store.NO, Field.Index.ANALYZED));
                // Desc
                var desc = node.SelectSingleNode("description");
                doc.Add(new Field("", desc.InnerText, Field.Store.NO, Field.Index.ANALYZED));

                foreach (XmlNode aNode in node.SelectNodes("a"))
                {
                    string key = aNode.Attributes["attCatID"].Value;
                    string value = aNode.Attributes["attValue"].Value;
                    if (string.IsNullOrEmpty(value))
                    {
                        continue;
                    }
                    switch (key)
                    {
                        case "speaker":
                            doc.Add(new Field("speaker", value, Field.Store.NO, Field.Index.NOT_ANALYZED));
                            break;

                        case "products":
                            doc.Add(new Field("", value, Field.Store.NO, Field.Index.ANALYZED));
                            break;
                        case "date":
                            doc.Add(new Field("time",
                                              DateTools.DateToString(DateTime.Parse(value), DateTools.Resolution.DAY),
                                              Field.Store.NO,
                                              Field.Index.NOT_ANALYZED_NO_NORMS));
                            break;

                        case "tech":
                            doc.Add(new Field("", value, Field.Store.NO, Field.Index.ANALYZED));
                            break;

                        case "series":
                            doc.Add(new Field("", value, Field.Store.NO, Field.Index.ANALYZED));
                            break;

                        case "rating":
                            doc.Add(new Field("rate", value, Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS));
                            break;

                        case "level":
                            doc.Add(new Field("level", value, Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS));
                            break;

                    }
                }

                writer.AddDocument(doc);
            }

            writer.Optimize();
            writer.Close();
            // Zip to wwwroot
            PackageIndexFile(dir);
        }

        private static void PackageIndexFile(RAMDirectory dir)
        {
            FileStream indexZipFS = new FileStream(_indexPath,
                                                   FileMode.Create,
                                                   FileAccess.Write,
                                                   FileShare.None,
                                                   1024,
                                                   FileOptions.None);

            ZipOutputStream zipOut = new ZipOutputStream(indexZipFS);
            zipOut.IsStreamOwner = true;

            int index = 0;
            byte[] buffer = new byte[4096];

            foreach (string name in dir.ListAll())
            {
                ZipEntry entry = new ZipEntry(name);
                entry.CompressionMethod = CompressionMethod.Deflated;
                zipOut.PutNextEntry(entry);

                IndexInput input = dir.OpenInput(name);
                long length = input.Length();
                long iRead = 0;
                while (iRead < length)
                {
                    int len = (int)(length - iRead) > 4096 ? 4096 : (int)(length - iRead);
                    input.ReadBytes(buffer, 0, len);
                    zipOut.Write(buffer, 0, len);

                    iRead += len;
                }
                index++;
            }

            // Add info.xml
            string infoPath = OriginalContentManager.Current.InfoXmlPath;
            using(FileStream fs = new FileStream(infoPath, FileMode.Open))
            {
                long length = fs.Length;
                long lenRead = 0;
                ZipEntry entry = new ZipEntry("info.xml");
                entry.CompressionMethod = CompressionMethod.Deflated;
                zipOut.PutNextEntry(entry);

                while (lenRead < length)
                {
                    int len = (int)(length - lenRead) > 4096 ? 4096 : (int)(length - lenRead);
                    int iRead = fs.Read(buffer, 0, len);
                    zipOut.Write(buffer, 0, iRead);
                    lenRead += iRead;
                }
                fs.Close();
            }
            zipOut.Finish();
            zipOut.Close();
        }
    }
}

